package com.ck.company.service.impl;

import com.ck.common.service.OperationLogService;
import com.ck.company.service.CpFileService;
import com.ck.company.service.CpSceneService;
import com.ck.config.CustomProperties;
import com.ck.constant.*;
import com.ck.dao.FileMapper;
import com.ck.exception.ServiceException;
import com.ck.model.common.File;
import com.ck.model.common.OperationLog;
import com.ck.model.common.User;
import com.ck.model.common.page.PageInfo;
import com.ck.model.company.dto.CpFileListDTO;
import com.ck.model.company.vo.CpFileListVO;
import com.ck.util.DateUtils;
import com.ck.util.FileUtils;
import com.ck.util.HuaWeiCloudUtils;
import com.ck.util.MultimediaUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author dxy
 * @date 2018/9/13 10:38
 */
@Service(value = "cpFileService")
public class CpFileServiceImpl implements CpFileService {
	@Autowired
	private FileMapper fileMapper;
	@Autowired
	private OperationLogService operationLogService;
	@Autowired
	private CustomProperties customProperties;
	@Autowired
	private CpSceneService cpSceneService;

	/**
	 * 上传文件(因为获取文件的通用属性，如果要获取时长，请另行获取)
	 *
	 * @param files        MultipartFile
	 * @param fileType     文件类型
	 * @param companyCode  商家编码
	 * @param cloudFileDir 云文件目录
	 * @param needDuration 是否需要时长
	 * @return Map<String, Object>
	 * @throws ServiceException
	 * @throws IOException
	 */
	@Override
	public Map<String, Object> uploadFile(MultipartFile files, Integer fileType, String companyCode, String cloudFileDir, boolean needDuration) throws ServiceException, IOException {
		if (files == null || fileType == null || StringUtils.isBlank(companyCode) || StringUtils.isBlank(cloudFileDir)) {
			throw new ServiceException("输入参数不能未空");
		}
		//获取文件名称
		String originalFilename = files.getOriginalFilename();
		//文件后缀
		String fileExtension = FilenameUtils.getExtension(originalFilename);
		//去掉扩展名的文件名
		String fileName = originalFilename.replaceAll("." + fileExtension, "");
		//校验文件名是否存在
		File oldFile = getFileByName(companyCode, fileType, fileExtension, fileName);
		//文件名存在
		if (oldFile != null) {
			//校验文件名是否与库中的同商家的文件文件名重复，如果重复，自动命名文件名，命名规则（a.jpg,a(1).jpg,a(2).jpg）
			//查找类型"a(1)"类似的文件，mysql匹配类型为“a(%)%”
			Long count = countFileLikeName(companyCode, fileType, fileExtension, fileName + "(%)");
			if (count != null) {
				fileName = fileName + "(" + (count + 1) + ")";
			}
		}
		//将MultipartFile转化为指定文件名的File
		java.io.File file = FileUtils.multipartFileConvertFile(files, fileName + "." + fileExtension);
		//将文件上传至华为云
		String url = HuaWeiCloudUtils.uploadFile2HuaweiCloud(file, cloudFileDir);
		//获取文件md5值
		String md5 = FileUtils.getFileMD5(file);
		//获取文件大小
		long length = file.length();
		Long duration = 0L;
		if (needDuration) {
			duration = MultimediaUtils.readFileDuration(file);
		}
		//获取时长
		//把MultipartFile转化为File,会在本地创建文件，用完file后，需要删除
		if (file.exists()) {
			file.delete();
		}
		//返回给前端使用
		Map<String, Object> fileMap = Maps.newHashMap();
		fileMap.put(FileConstant.URL, url);
		fileMap.put(FileConstant.FILE, url);
		fileMap.put(FileConstant.MD5, md5);
		fileMap.put(FileConstant.SIZE, length);
		fileMap.put(FileConstant.DURATION, duration);
		fileMap.put(FileConstant.FILE_NAME, fileName);
		fileMap.put(FileConstant.FILE_SUFFIX, fileExtension);
		fileMap.put(FileConstant.FILE_TYPE, fileType);
		return fileMap;
	}

	/**
	 * 保存文件
	 *
	 * @param file      File
	 * @param loginUser User
	 * @param remoteIp  远程ip
	 * @throws ServiceException
	 */
	@Override
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void saveFile(File file, User loginUser, String remoteIp) throws ServiceException {
		if (file == null || loginUser == null || StringUtils.isBlank(remoteIp)) {
			throw new ServiceException("输入参数不能为空");
		}
		String companyCode = loginUser.getCompanyCode();
		file.setCompanyCode(companyCode);
		file.setAddTime(System.currentTimeMillis());
		fileMapper.insertFile(file);
		//记录操作日志
		OperationLog operationLog = new OperationLog();
		operationLog.setCopmanyCode(companyCode);
		String content = "";
		Integer fileType = file.getFileType();
		if (FileConstant.FILE_TYPE_DOCUMENT == fileType) {
			content = "保存文档文件，文档文件名为：" + file.getFileName() + "." + file.getFileSuffix();
			operationLog.setOperationModule(ModuleConstant.MODULE_MATERIAL + "-" + ModuleConstant.MODULE_DEPARTMENT);
		}
		if (FileConstant.FILE_TYPE_AUDIO == fileType) {
			content = "保存音频文件，音频文件名为：" + file.getFileName() + "." + file.getFileSuffix();
			operationLog.setOperationModule(ModuleConstant.MODULE_MATERIAL + "-" + ModuleConstant.MODULE_AUDIO);
		}
		operationLog.setOperationContent(content);
		operationLog.setOperationStatus(BusinessConstant.OPERATION_LONG_OPERATION_STATUS_SUCCESS);
		operationLog.setOperationTime(System.currentTimeMillis());
		operationLog.setRealname(loginUser.getRealname());
		operationLog.setUserName(loginUser.getUserName());
		operationLog.setOperationIp(remoteIp);
		operationLogService.saveOperationLog(operationLog);
	}

	/**
	 * 通过ID修改文件
	 * @param file      File
	 * @param loginUser User
	 * @param remoteIp  远程ip
	 * @param fileType  文件类型
	 * @throws ServiceException
	 */
	@Override
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void updateFileById(File file, User loginUser, String remoteIp, Integer fileType) throws ServiceException {
		if (file == null || loginUser == null || StringUtils.isBlank(remoteIp) || fileType == null) {
			throw new ServiceException("输入参数不能为空");
		}
		Long fileId = file.getFileId();
		if (fileId == null) {
			throw new ServiceException("文件ID不能为空");
		}
		File oldFile = getFileById(fileId);
		if (oldFile == null) {
			throw new ServiceException("文件不存在，请联系管理员");
		}
		//更新到数据库
		fileMapper.updateFileById(file);
		//商家编码
		String companyCode = loginUser.getCompanyCode();
		//文件后缀
		String fileSuffix = oldFile.getFileSuffix();
		//记录操作日志
		OperationLog operationLog = new OperationLog();
		operationLog.setCopmanyCode(companyCode);
		String content = "";
		if (FileConstant.FILE_TYPE_DOCUMENT == fileType) {
			content = "重命名文档文件，将文档文件：" + oldFile.getFileName() + "." + fileSuffix + "，命名为：" + file.getFileName() + "." + fileSuffix;
			operationLog.setOperationModule(ModuleConstant.MODULE_MATERIAL + "-" + ModuleConstant.MODULE_DEPARTMENT);
		}
		if (FileConstant.FILE_TYPE_AUDIO == fileType) {
			content = "重命名音频文件，将音频文件：" + oldFile.getFileName() + "." + fileSuffix + "，命名为：" + file.getFileName() + "." + fileSuffix;
			operationLog.setOperationModule(ModuleConstant.MODULE_MATERIAL + "-" + ModuleConstant.MODULE_AUDIO);
		}
		operationLog.setOperationContent(content);
		operationLog.setOperationStatus(BusinessConstant.OPERATION_LONG_OPERATION_STATUS_SUCCESS);
		operationLog.setOperationTime(System.currentTimeMillis());
		operationLog.setRealname(loginUser.getRealname());
		operationLog.setUserName(loginUser.getUserName());
		operationLog.setOperationIp(remoteIp);
		operationLogService.saveOperationLog(operationLog);
	}

	/**
	 * 通过名字获取文件
	 *
	 * @param companyCode 公司编码
	 * @param fileType
	 * @param fileSuffix
	 * @param fileName    文件名称
	 * @return File
	 * @throws ServiceException
	 */
	@Override
	public File getFileByName(String companyCode, Integer fileType, String fileSuffix, String fileName) throws ServiceException {
		if (StringUtils.isBlank(companyCode) || fileType == null
				|| StringUtils.isBlank(fileSuffix) || StringUtils.isBlank(fileName)) {
			throw new ServiceException("输入参数不能为空");
		}
		return fileMapper.getFileByName(companyCode, fileType, fileSuffix, fileName);
	}

	/**
	 * 获取文件列表
	 *
	 * @param companyCode 公司编码
	 * @param fileType    文件类型
	 * @param fileName    文件名
	 * @param pageNum     当前页
	 * @param pageSize    条数
	 * @return List<CpFileListDTO>
	 * @throws ServiceException
	 */
	@Override
	public PageInfo<CpFileListVO> listFile(String companyCode, Integer fileType, String fileName, Integer pageNum, Integer pageSize) throws ServiceException {
		if (StringUtils.isBlank(companyCode)) {
			throw new ServiceException("公司编码不能为空");
		}
		if (fileType == null) {
			throw new ServiceException("文件类型不能为空");
		}
		if (pageNum == null) {
			pageNum = PageConstant.DEFAULT_PAGE_NUM;
		}
		if (pageSize == null) {
			pageSize = PageConstant.DEFAULT_PAGE_SIZE;
		}
		//分页
		PageHelper.startPage(pageNum, pageSize);
		Page<CpFileListDTO> page = fileMapper.listFile(companyCode, fileType, fileName);
		PageInfo<CpFileListVO> pageInfo = new PageInfo();
		pageInfo.setPageNum(pageNum);
		pageInfo.setPageSize(pageSize);
		pageInfo.setTotal(page.getTotal());
		List<CpFileListDTO> result = page.getResult();
		if (CollectionUtils.isEmpty(result)) {
			pageInfo.setList(new ArrayList<>());
		} else {
			List<CpFileListVO> voList = new ArrayList<>();
			for (CpFileListDTO dto : result) {
				CpFileListVO vo = new CpFileListVO();
				vo.setFileId(dto.getFileId());
				vo.setFileName(dto.getFileName() + "." + dto.getFileSuffix());
				vo.setFileType(dto.getFileType());
				Long longSize = dto.getSize();
				double  doubleSize = longSize.doubleValue();
				double size = doubleSize / 1024 / 1024;
				DecimalFormat df = new DecimalFormat("0.00");
				String formatSize = df.format(size);
				vo.setSize(formatSize + "M");
				vo.setUrl(dto.getUrl());
				vo.setAddTime(DateUtils.longTimeStampToStringDate(dto.getAddTime(), DateFormatConstant.LONG_DATE_FORMAT_STR));
				voList.add(vo);
			}
			pageInfo.setList(voList);
		}
		return pageInfo;
	}

	/**
	 * 通过相似文件名获取文件总数
	 *
	 * @param companyCode 公司编码
	 * @param fileType
	 * @param fileSuffix
	 * @param fileName    文件名称
	 * @return Long
	 * @throws ServiceException
	 */
	@Override
	public Long countFileLikeName(String companyCode, Integer fileType, String fileSuffix, String fileName) throws ServiceException {
		if (StringUtils.isBlank(companyCode) || fileType == null
				|| StringUtils.isBlank(fileSuffix) || StringUtils.isBlank(fileName)) {
			throw new ServiceException("输入参数不能为空");
		}
		return fileMapper.countFileLikeName(companyCode, fileType, fileSuffix, fileName);
	}

	/**
	 * 重命名文件
	 * @param fileId      文件ID
	 * @param fileNewName 文件新名称
	 * @return Map<String, Object>
	 * @throws ServiceException
	 */
	@Override
	public Map<String, Object> renameFileAndUpload(Long fileId, String fileNewName, String cloudFileDir) throws ServiceException, IOException {
		if (fileId == null || StringUtils.isBlank(fileNewName)) {
			throw new ServiceException("输入参数不能为空");
		}
		File file = getFileById(fileId);
		if (file == null) {
			throw new ServiceException("文件不存在，请联系管理员");
		}
		//文件Map
		Map<String, Object> fileMap = new HashMap<>(1);
		//文件临时存放目录
		String fileTempSaveDir = customProperties.getFileTempSaveDir();
		String separator = java.io.File.separator;
		if (!fileTempSaveDir.endsWith(separator)) {
			fileTempSaveDir = fileTempSaveDir + separator;
		}
		//地址(存放地址)
		String url = file.getUrl();
		//文件名
		String oldVideoName = file.getFileName();
		String filePath = fileTempSaveDir + oldVideoName;
		//文件后缀
		String fileSuffix = file.getFileSuffix();
		//文件绝对路径
		String fullPath = filePath + "." + fileSuffix;
		//下载源文件
		FileUtils.downloadFileFromURL(url, fullPath);
		//重命名后文件名称
		String fullVideoNewName = fileNewName + "." + fileSuffix;
		//重命名文件
		Path path = Paths.get(fullPath);
		Files.move(path, path.resolveSibling(fullVideoNewName));
		//将重命名的文件上传至华为云
		java.io.File newFile = new java.io.File(fileTempSaveDir + fullVideoNewName);
		if (newFile.exists()) {
			url = HuaWeiCloudUtils.uploadFile2HuaweiCloud(newFile, cloudFileDir);
			fileMap.put(FileConstant.URL, url);
			//删除本地临时文件
			newFile.delete();
		}
		return fileMap;
	}

	/**
	 * 通过文件ID获取文件
	 *
	 * @param fileId 文件ID
	 * @return File
	 * @throws ServiceException
	 */
	@Override
	public File getFileById(Long fileId) throws ServiceException {
		if (fileId == null) {
			throw new ServiceException("文件ID不能为空");
		}
		return fileMapper.getFileById(fileId);
	}

	/**
	 * 删除文件
	 * @param fileId 文件ID
	 * @param loginUser User
	 * @param remoteIp 远程ip
	 * @throws ServiceException
	 */
	@Override
	public void deleteFile(Long fileId, User loginUser, String remoteIp) throws ServiceException, IOException {
		if (fileId == null || loginUser == null || remoteIp == null) {
			throw new ServiceException("输入参数不能为空");
		}
		//检查文件是否存在
		File file = getFileById(fileId);
		if (file == null) {
			throw new ServiceException("数据不存在，请联系管理员");
		}
		//地址
		String url = file.getUrl();
		//如果URL地址不为空，则需要删除云上的数据
		if (StringUtils.isNotBlank(url)) {
			//校验文件是被使用，如果再使用，则不能被删除（请查看具体的sql语句）
			Long count = cpSceneService.countNoDeleteProgram(url);
			if (count > 0) {
				throw new ServiceException("文件正在被使用，不能被删除");
			}
			//文件类型
			Integer fileType = file.getFileType();
			//文件名
			String fileName = file.getFileName();
			//文件后缀
			String fileSuffix = file.getFileSuffix();
			//商家编码
			String companyCode = loginUser.getCompanyCode();
			//文件云路径
			String fileCloudPath = "";
			if (FileConstant.FILE_TYPE_DOCUMENT == fileType) {
				fileCloudPath = companyCode + "/document/" + fileName + "." + fileSuffix;
			}
			if (FileConstant.FILE_TYPE_AUDIO == fileType) {
				fileCloudPath = companyCode + "/audio/" + fileName + "." + fileSuffix;
			}
			//删除云上的数据
			if (StringUtils.isNotBlank(fileCloudPath)) {
				HuaWeiCloudUtils.deleteHuaweiCloudObject(fileCloudPath);
			}
		}
		//删除数据库中的数据
		deleteFileById(fileId, loginUser, remoteIp);
	}

	/**
	 * 通过ID删除文件
	 * @param fileId 文件ID
	 * @param loginUser User
	 * @param remoteIp 远程ip
	 * @throws ServiceException
	 */
	@Override
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void deleteFileById(Long fileId, User loginUser, String remoteIp) throws ServiceException {
		if (fileId == null || loginUser == null || StringUtils.isBlank(remoteIp)) {
			throw new ServiceException("输入参数不能为空");
		}
		//检查文件是否存在
		File file = getFileById(fileId);
		if (file == null) {
			throw new ServiceException("数据不存在，请联系管理员");
		}
		//删除数据库中的数据
		fileMapper.deleteFileById(fileId);
		//文件类型
		Integer fileType = file.getFileType();
		//文件名称
		String fileName = file.getFileName();
		//文件后缀
		String fileSuffix = file.getFileSuffix();
		//商家编码
		String companyCode = loginUser.getCompanyCode();
		//记录操作日志
		OperationLog operationLog = new OperationLog();
		operationLog.setCopmanyCode(companyCode);
		String content = "";
		if (FileConstant.FILE_TYPE_DOCUMENT == fileType) {
			content = "删除文档文件，文档文件名为:" + fileName + "." + fileSuffix;
			operationLog.setOperationModule(ModuleConstant.MODULE_MATERIAL + "-" + ModuleConstant.MODULE_DOCUMENT);
		}
		if (FileConstant.FILE_TYPE_AUDIO ==  fileType) {
			content = "删除音频文件，音频文件名为:" + fileName + "." + fileSuffix;
			operationLog.setOperationModule(ModuleConstant.MODULE_MATERIAL + "-" + ModuleConstant.MODULE_AUDIO);
		}
		operationLog.setOperationContent(content);
		operationLog.setOperationStatus(BusinessConstant.OPERATION_LONG_OPERATION_STATUS_SUCCESS);
		operationLog.setOperationTime(System.currentTimeMillis());
		operationLog.setRealname(loginUser.getRealname());
		operationLog.setUserName(loginUser.getUserName());
		operationLog.setOperationIp(remoteIp);
		operationLogService.saveOperationLog(operationLog);
	}
}
